/**
 * PHOSIDE: PHosphorylation Site IDentification Engine.
 * Copyright 2009 Digital Biology Lab, University of Missouri.
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version. <p/> This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more
 * details.
 */

package phoside.data.feature.extaction;

import java.io.Serializable;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

import phoside.Protein;

import phoside.data.feature.model.Instance;
import phoside.data.feature.model.InstanceTag;

import phoside.util.ProteinSequenceUtil;
import phoside.util.StaticFinalValues;

/**
 *
 * @author gjj
 */
public class DisorderFeatureExtractor implements FeatureExtractor, Serializable {
    private static final long serialVersionUID = -6518622392591723991L;

    protected final boolean useAverage;
    protected final TreeSet<Integer> selectedWindowOffsets;

    public DisorderFeatureExtractor (final int[] selectedWindowOffsets,
                                     final boolean useAverage) {

        if (selectedWindowOffsets==null) {
            throw new NullPointerException();
        }

        this.useAverage = useAverage;
        this.selectedWindowOffsets = new TreeSet<Integer>();
        for (int offset : selectedWindowOffsets) {
            this.selectedWindowOffsets.add(offset);
        }

    }

    /**
     * Extract features from protein at site and save to instance
     * @param protein
     * @param site
     * @param savetoInstance
     */
    public List<Double> extract(final Instance instance, final boolean save) {
        if (instance==null) {
            throw new NullPointerException();
        }

        InstanceTag instanceTag = instance.getInstanceTag();
        Object obj = instanceTag.getTag(StaticFinalValues.INSTANCETAGNAMEPROTEIN);
        if (!(obj instanceof Protein)) {
            throw new java.lang.UnsupportedOperationException();
        }
        Protein protein = (Protein)obj;

        obj = instanceTag.getTag(StaticFinalValues.INSTANCETAGNAMESITE);
        if (!(obj instanceof Integer)) {
            throw new java.lang.UnsupportedOperationException();
        }
        int site = (Integer)obj;

        obj = protein.getInfo(StaticFinalValues.DISORDER);
        if (obj == null) {
            return null;
        }

        List<Double> dis = (List<Double>)obj;

        int len = dis.size();
        int minOffset = selectedWindowOffsets.first();
        int maxOffset = selectedWindowOffsets.last();

        ArrayList<Double> features = new ArrayList<Double>();

        if (useAverage) {            
            if (minOffset<0) {
                throw new IndexOutOfBoundsException();
            }

            double sum = dis.get(site);
            if (selectedWindowOffsets.contains(0)) {
                features.add(sum);
            }

            int count = 1;
            String seq = protein.getSequence();
            for (int offset=1; offset<=maxOffset; offset++) {
                if (site-offset>=0) {
                    sum += dis.get(site-offset);
                    count++;
                }

                if (site+offset<len) {
                    sum += dis.get(site+offset);
                    count++;
                }

                if (selectedWindowOffsets.contains(offset)) {
                    double ave = sum/count;
                    features.add(ave);
                }
            }
        } else {
            for (int offset : selectedWindowOffsets) {
                if (site+offset<0) {
                    features.add(dis.get(0));
                } if (site+offset>=len) {
                    features.add(dis.get(len-1));
                } else {
                    features.add(dis.get(site+offset));
                }
            }
        }


        if (save) {
            instance.putFeatures(featureTag(), features);
        }

        return features;
    }

    /**
     *
     * @return
     */
    public String featureTag() {
        return StaticFinalValues.DISORDER;
    }
}
